#ifndef RING_QUEUE_HPP
#define RING_QUEUE_HPP
#include <pthread.h>
#include <semaphore.h>

#include <vector>

// 定义一个模板类 RingQueue，可以存储任意类型 T 的数据
template <class T>
class RingQueue {
  const static int defaultnum = 10;  // 默认队列大小

 private:
  // 封装信号量的 P 操作（等待）
  void P(sem_t &sem) { sem_wait(&sem); }
  // 封装信号量的 V 操作（释放）
  void V(sem_t &sem) { sem_post(&sem); }
  // 封装互斥锁的加锁操作
  void Lock(pthread_mutex_t &mutex) { pthread_mutex_lock(&mutex); }
  // 封装互斥锁的解锁操作
  void Unlock(pthread_mutex_t &mutex) { pthread_mutex_unlock(&mutex); }

 public:
  // 构造函数，初始化队列和同步原语
  RingQueue(int maxcap = defaultnum)
      : queue_(maxcap), maxcap_(maxcap), cstep_(0), pstep_(0) {
    sem_init(&sem_data_, 0, 0);  // 初始化数据信号量，初始值为0
    sem_init(&sem_space_, 0, maxcap_);  // 初始化空间信号量，初始值为最大容量
    pthread_mutex_init(&c_lock_, nullptr);  // 初始化消费者互斥锁
    pthread_mutex_init(&p_lock_, nullptr);  // 初始化生产者互斥锁
  }

  // 生产者方法：向队列中添加数据
  void Push(const T &data) {
    P(sem_space_);  // 等待有可用空间
    Lock(p_lock_);  // 加锁，确保生产者之间互斥

    queue_[pstep_] = data;            // 将数据放入队列
    pstep_ = (pstep_ + 1) % maxcap_;  // 更新生产者索引，保持环形

    V(sem_data_);     // 增加可用数据的信号量
    Unlock(p_lock_);  // 解锁
  }

  // 消费者方法：从队列中取出数据
  void Pop(T *out) {
    P(sem_data_);   // 等待有可用数据
    Lock(c_lock_);  // 加锁，确保消费者之间互斥

    *out = queue_[cstep_];            // 取出数据
    cstep_ = (cstep_ + 1) % maxcap_;  // 更新消费者索引，保持环形

    Unlock(c_lock_);  // 解锁
    V(sem_space_);    // 增加可用空间的信号量
  }

  // 析构函数，清理资源
  ~RingQueue() {
    sem_destroy(&sem_data_);          // 销毁数据信号量
    sem_destroy(&sem_space_);         // 销毁空间信号量
    pthread_mutex_destroy(&c_lock_);  // 销毁消费者互斥锁
    pthread_mutex_destroy(&p_lock_);  // 销毁生产者互斥锁
  }

 private:
  std::vector<T> queue_;    // 存储数据的环形队列
  int maxcap_;              // 队列最大容量
  int cstep_;               // 消费者当前位置
  int pstep_;               // 生产者当前位置
  sem_t sem_data_;          // 可用数据的信号量
  sem_t sem_space_;         // 可用空间的信号量
  pthread_mutex_t c_lock_;  // 消费者互斥锁
  pthread_mutex_t p_lock_;  // 生产者互斥锁
};

#endif
